﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using UtfprLibrary.Windows.Forms.ComponentModel;
using System.Drawing.Design;

namespace UtfprLibrary.Windows.Forms {
    /// <summary>
    /// TODO
    /// </summary>
    [DefaultProperty("ValidatableControlCollection")]
    public abstract class UBNCollectionBaseValidator : Component {
        #region PropertiesToOverride

        public abstract UBNValidatableControlCollection ValidatableControlCollection { get; set; }

        #endregion

        private static ErrorProvider _errorProvider = new ErrorProvider();

        /// <summary>
        /// TODO
        /// </summary>
        public UBNCollectionBaseValidator() {
            //ValidatableControlCollection.Adding += new UBNValidatableControlCollection.AddingEventHandler(ValidatableControlCollection_Adding);
        }

        private bool cancelFocus = true;
        /// <summary>
        /// TODO
        /// </summary>
        [Category("Behavior")]
        [Description("Habilita ou não a mudança de foco em um controle")]
        public bool CancelFocusChangeWhenInvalid {
            get { return cancelFocus; }
            set { cancelFocus = value; }
        }

        //private Icon _icon = new Icon(typeof(ErrorProvider), "Error.png");
        private Icon _icon = Icon.FromHandle(Core.Properties.Resources.ERR_Exclamation.GetHicon());

        /// <summary>
        /// TODO
        /// </summary>
        [Category("Layout")]
        [Description("O ícone da mensagem de erro.")]
        public Icon Icon {
            get { return _icon; }
            set { _icon = value; }
        }

        private UtfprBindingNavigatorBase _utfprBindingNavigator;
        /// <summary>
        /// TODO
        /// </summary>
        [Category("Behavior")]
        [Description("Coleção de controles marcados para a validação")]
        public UtfprBindingNavigatorBase UtfprBindingNavigator {
            get { return _utfprBindingNavigator; }
            set {
                if (ValidatableControlCollection != null) {
                    ValidatableControlCollection.Clear();
                }
                _utfprBindingNavigator = value;
            }
        }

        ///// <summary>
        ///// TODO
        ///// </summary>
        ///// <param name="sender"></param>
        ///// <param name="args"></param>
        //private void ValidatableControlCollection_Adding(object sender, AddingChangedEventArgs args) {
        //    if (!DesignMode) {
        //        if (_validatableControlCollection.Count > 0) {
        //            foreach (UtfprValidatableControl uvc in _validatableControlCollection) {
        //                args.ValidatableControl.Control.Validating += new CancelEventHandler(ControlToValidate_Validating);
        //            }
        //        }
        //    }
        //}

        private Dictionary<Control, bool> _areValid = new Dictionary<Control, bool>();
        /// <summary>
        /// TODO
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public Dictionary<Control, bool> AreValid {
            get { return _areValid; }
            set { _areValid = value; }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <returns></returns>
        protected abstract Dictionary<Control, bool> EvaluateAreValid();

        /// <summary>
        /// TODO
        /// </summary>
        public void CancelValidation() {
            //foreach (UtfprValidatableControl v in ValidatableControlCollection) {
            //    v.Control.Invalidate();
            //}

            _errorProvider.Clear();
        }

        /// <summary>
        /// TODO
        /// </summary>
        public void Validate() {
            _areValid = EvaluateAreValid();

            foreach (var v in _areValid) {
                int index = ValidatableControlCollection.GetItemIndex(v.Key);

                string errorMessage = ValidatableControlCollection[index].ErrorMessage;
                Control controlToValidate = ValidatableControlCollection[index].Control;

                if (v.Value == false) {
                    _errorProvider.SetError(controlToValidate, errorMessage);
                } else {
                    _errorProvider.SetError(controlToValidate, "");
                }
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="controlToValidate"></param>
        private void Validate(Control controlToValidate) {
            bool _isValid = EvaluateAreValid()[controlToValidate];

            int index = ValidatableControlCollection.GetItemIndex(controlToValidate);

            string errorMessage = "";
            if (!_isValid) {
                errorMessage = ValidatableControlCollection[index].ErrorMessage;
                _errorProvider.Icon = _icon;
            }

            _errorProvider.SetError(controlToValidate, errorMessage);
        }

        ///// <summary>
        ///// TODO
        ///// </summary>
        ///// <param name="sender"></param>
        ///// <param name="e"></param>
        //private void ControlToValidate_Validating(object sender, CancelEventArgs e) {
        //    // We don't cancel if invalid since we don't want to force
        //    // the focus to remain on ControlToValidate if invalid
        //    Validate(sender as Control);

        //    // Se os dados forem inválidos, cancela o foco, baseando-se no comportamento desejado
        //    if (!EvaluateAreValid()[sender as Control] && cancelFocus) {
        //        e.Cancel = true;
        //    }
        //}

        /// <summary>
        /// Certifica-se que toda a validação está do formulário está OK
        /// </summary>
        /// <param name="formComponents">O container do formulário.</param>
        /// <returns>True ou False</returns>
        public static bool IsFormValid(IContainer formComponents) {
            bool invalidInput = false;

            // Certifica-se que toda a validação está OK
            foreach (IComponent component in formComponents.Components) {
                UBNCollectionBaseValidator validator = component as UBNCollectionBaseValidator;
                if (validator != null) {
                    foreach (var validatedControls in validator.EvaluateAreValid()) {
                        //se não for válido
                        if (!validatedControls.Value) {
                            //marca como inválido
                            invalidInput = true;
                        }
                    }
                }
            }

            return !invalidInput;
        }
    }
}

